#include "ScnsXpt2046.c.h"

#if defined(SCNS_XPT2046_ENABLE)&&SCNS_XPT2046_ENABLE==1

//@scnsBsp:https://gitee.com/huoxingdawang/scnsDemos-MM32F3277_seekfree/tree/master/Libraries/scnsBsp/MM32F3277_seekfree/

#include "ScnsTimer.h"
#include "ScnsMath.h"
#include "ScnsTouchScreen.h"
#include "ScnsLcd.h"

static struct
{
    uint8 inited;
    uint8 pCnt;
    Point p[4];
    uint64 lastUs;
}rd[SCNS_XPT2046_MAX];

ScnsXpt2046Result scnsXpt2046Result[SCNS_XPT2046_MAX];

#define scl(x)  scnsBspXpt2046SetScl(xptN,(x))
#define cs(x)   scnsBspXpt2046SetCs(xptN,(x))
#define mosi(x) scnsBspXpt2046SetMosi(xptN,(x))
#define miso()  scnsBspXpt2046GetMiso(xptN)

static void WB(ScnsXpt2046Enum xptN,uint8 num)
{
    for(uint8 c=0;c<8;++c)
    {
        mosi((num&0x80)?1:0);
        num<<=1;
        scl(0);
        scnsDelayUs(1);
        scl(1);
    }
}

static uint16 readAd(ScnsXpt2046Enum xptN,uint8 cmd)
{
    uint16 num=0;
    scl(0);
    mosi(0);
    cs(0);
    WB(xptN,cmd);
    scnsDelayUs(6);
    scl(0);
    scnsDelayUs(1);
    scl(1);
    scnsDelayUs(1);
    scl(0);
    for(uint8 c=0;c<16;c++)
    {
        num<<=1;
        scl(0);
        scnsDelayUs(1);
        scl(1);
        num|=((miso())?(1):(0));
    }
    num>>=4;
    cs(1);
    return (num);
}

static Point readP(ScnsXpt2046Enum xpt,const uint8 ch[])
{
    return (Point){
        .x=  readAd(xpt,ch[0]),
        .y=  readAd(xpt,ch[1]),
    };
}

#define rdP(x)  (rd[xptN].p[x])
#define cof     (scnsBspXpt2046Config[xptN])

ScnsXpt2046Status scnsXpt2046Init(ScnsXpt2046Enum xptN)
{
    SCNS_ASSERT_ON_RUN(xptN<SCNS_XPT2046_MAX);
    scnsCheck(ScnsXpt2046Status,scnsBspXpt2046Init(xptN),SCNS_XPT2046_STATUS_OK);
    if(cof.ch!=0&&cof.ch!=1&&cof.ch!=2)
        return SCNS_XPT2046_STATUS_FAILED;
    scnsCheck(ScnsXpt2046Status,scnsBspXpt2046PostInit(xptN),SCNS_XPT2046_STATUS_OK);
    rd[xptN].inited=1;
    return SCNS_XPT2046_STATUS_OK;
}

void scnsXpt2046Scan(ScnsXpt2046Enum xptN)
{
    SCNS_ASSERT_ON_RUN(xptN<SCNS_XPT2046_MAX);
    if(rd[xptN].inited!=1)return;
    if(cof.ch!=1&&cof.ch!=2)return;
    if((scnsTimerGetUs()-rd[xptN].lastUs)<=1000)return;
    rd[xptN].lastUs=scnsTimerGetUs();
    if(scnsBspXpt2046GetPen(xptN)==0)
    {
        scnsBspXpt2046Begin(xptN);
        static const uint8 ch[2][2]={
            {0X90,0XD0},
            {0XD0,0X90},
        };
        rd[xptN].p[rd[xptN].pCnt]=readP(xptN,ch[cof.ch-1]);
        rd[xptN].pCnt=(rd[xptN].pCnt+1)&0X3;
        scnsBspXpt2046End(xptN);
        if(rd[xptN].pCnt==0)
        {
            scnsXpt2046Result[xptN].down=1;
            scnsXpt2046Result[xptN].p.x=cof.xa+cof.xb*((rdP(0).x+rdP(1).x+rdP(2).x+rdP(3).x)/4);
            scnsXpt2046Result[xptN].p.y=cof.ya+cof.yb*((rdP(0).y+rdP(1).y+rdP(2).y+rdP(3).y)/4);
            //const uint16 xArg1=(rdP(0).x+rdP(1).x+rdP(2).x+rdP(3).x)/4;
            //const uint16 xArg2=(rdP(4).x+rdP(5).x+rdP(6).x+rdP(7).x)/4;
            //const uint16 yArg1=(rdP(0).y+rdP(1).y+rdP(2).y+rdP(3).y)/4;
            //const uint16 yArg2=(rdP(4).y+rdP(5).y+rdP(6).y+rdP(7).y)/4;
            //const int16 dx=xArg1-xArg2;
            //const int16 dy=yArg1-yArg2;
            //if(dx>=-100&&dx<=100&&dy>=-100&&dy<=100)
            //{
            //    aaaa.x=(xArg1+xArg2)/2;
            //    aaaa.y=(yArg1+yArg2)/2;
            //}
#if defined(SCNS_TOUCH_SCREEN_ENABLE)&&SCNS_TOUCH_SCREEN_ENABLE==1
            scnsTouchScreenUpdate((ScnsTouchScreenSource){.p={.x=scnsXpt2046Result[xptN].p.x,.y=scnsXpt2046Result[xptN].p.y}});
#endif
        }
    }
    else
    {
        rd[xptN].pCnt=0;
        scnsXpt2046Result[xptN].down=0;
        scnsXpt2046Result[xptN].p.x=0;
        scnsXpt2046Result[xptN].p.y=0;
    }
}

#if defined(SCNS_LCD_ENABLE)&&SCNS_LCD_ENABLE==1

static void nihe(float*aa,float*bb,unsigned int n,const uint16 xx[],const uint16 yy[])
{
    float sumXY=0,sumXX=0,sumX=0,sumY=0;
    for(unsigned int i=0;i<n;++i)
    {
        const float x=xx[i];
        const float y=yy[i];
        sumX+=x;
        sumY+=y;
        sumXY+=x*y;
        sumXX+=x*x;
    }
    float b=(sumXY-n*(sumX/n)*(sumY/n))/(sumXX-n*(sumX/n)*(sumX/n));
    float a=(sumY/n)-b*(sumX/n);
    *aa=a;
    *bb=b;
}

void scnsXptCorrection(ScnsXpt2046Enum xptN,ScnsLcdLayer layN,Point plu,Point prd)
{
    SCNS_ASSERT_ON_RUN(xptN<SCNS_XPT2046_MAX);
    if(rd[xptN].inited!=1)return;
    rd[xptN].inited=2;
    
    const int16 dx=prd.x-plu.x+1;
    const int16 dy=prd.y-plu.y+1;
    if(dx<=32||dy<32)
        return;
    scnsLcdFill(layN,plu,dx-1,dy-1,SCNS_LCD_COLOR_BACKGROUND,0);
    const Point target[9]={
        {.x=plu.x+dx*0.2,.y=plu.y+scnsMax(dy*0.2,16)},
        {.x=plu.x+dx*0.5,.y=plu.y+scnsMax(dy*0.2,16)},
        {.x=plu.x+dx*0.8,.y=plu.y+scnsMax(dy*0.2,16)},
        {.x=plu.x+dx*0.2,.y=plu.y+scnsMax(dy*0.5,16)},
        {.x=plu.x+dx*0.5,.y=plu.y+scnsMax(dy*0.5,16)},
        {.x=plu.x+dx*0.8,.y=plu.y+scnsMax(dy*0.5,16)},
        {.x=plu.x+dx*0.2,.y=plu.y+scnsMax(dy*0.8,16)},
        {.x=plu.x+dx*0.5,.y=plu.y+scnsMax(dy*0.8,16)},
        {.x=plu.x+dx*0.8,.y=plu.y+scnsMax(dy*0.8,16)},
    };
    Point data[(sizeof target)/(sizeof target[0])];
    for(uint8 stage=0;stage<(sizeof target)/(sizeof target[0]);++stage)
    {
        scnsLcdDisplayUint8(layN,scnsLcdDisplayString(layN,plu,"stage",&scnsLcdFontSimSun16,SCNS_LCD_COLOR_RED,SCNS_LCD_COLOR_BACKGROUND,0),stage+1,&scnsLcdFontSimSun16,SCNS_LCD_COLOR_RED,SCNS_LCD_COLOR_BACKGROUND,0);
        scnsLcdDisplayBigPoint(layN,target[stage],SCNS_LCD_COLOR_BLUE);
restart:;
        uint32 cnt=0;
        uint32 sumX=0,sumY=0;
        while(scnsBspXpt2046GetPen(xptN)!=0);
        scnsBspXpt2046Begin(xptN);
        for(const uint64 t=scnsTimerGetUs()+500*1000;scnsTimerGetUs()<=t;)
        {
            if(scnsBspXpt2046GetPen(xptN)!=0)
                goto restart;
            static const uint8 ch[2]={0X90,0XD0,};
            const Point p=readP(xptN,ch);
            ++cnt;
            sumX+=p.x;
            sumY+=p.y;
        }
        scnsBspXpt2046End(xptN);
        scnsLcdDisplayString(layN,plu,"done  ",&scnsLcdFontSimSun16,SCNS_LCD_COLOR_RED,SCNS_LCD_COLOR_BACKGROUND,0);
        while(scnsBspXpt2046GetPen(xptN)==0);
        data[stage].x=sumX/cnt;
        data[stage].y=sumY/cnt;
        scnsLcdDisplayBigPoint(layN,target[stage],SCNS_LCD_COLOR_BACKGROUND);
        printfFL("stage:%d,%d\r\n",data[stage].x,data[stage].y);
    }
    const uint8 ch=(scnsAbs(data[2].x-data[0].x)<scnsAbs(data[2].y-data[0].y))?1:0;
    printfFL("{.ch=%d,",ch+1);
    if(ch==0)   //x->x,y->y
    {
        {
            uint16 xx[(sizeof target)/(sizeof target[0])],yy[(sizeof target)/(sizeof target[0])];
            for(unsigned int i=0;i<(sizeof target)/(sizeof target[0]);++i)
            {
                xx[i]=data[i].x;
                yy[i]=target[i].x;
            }
            float a,b;
            nihe(&a,&b,(sizeof target)/(sizeof target[0]),xx,yy);
            printf(".xa=%e,.xb=%e,",a,b);
        }
        {
            uint16 xx[(sizeof target)/(sizeof target[0])],yy[(sizeof target)/(sizeof target[0])];
            for(unsigned int i=0;i<(sizeof target)/(sizeof target[0]);++i)
            {
                xx[i]=data[i].y;
                yy[i]=target[i].y;
            }
            float a,b;
            nihe(&a,&b,(sizeof target)/(sizeof target[0]),xx,yy);
            printf(".ya=%e,.yb=%e,",a,b);
        }
    }
    else
    {
        {
            uint16 xx[(sizeof target)/(sizeof target[0])],yy[(sizeof target)/(sizeof target[0])];
            for(unsigned int i=0;i<(sizeof target)/(sizeof target[0]);++i)
            {
                xx[i]=data[i].y;
                yy[i]=target[i].x;
            }
            float a,b;
            nihe(&a,&b,(sizeof target)/(sizeof target[0]),xx,yy);
            printf(".xa=%e,.xb=%e,",a,b);
        }
        {
            uint16 xx[(sizeof target)/(sizeof target[0])],yy[(sizeof target)/(sizeof target[0])];
            for(unsigned int i=0;i<(sizeof target)/(sizeof target[0]);++i)
            {
                xx[i]=data[i].x;
                yy[i]=target[i].y;
            }
            float a,b;
            nihe(&a,&b,(sizeof target)/(sizeof target[0]),xx,yy);
            printf(".ya=%e,.yb=%e,",a,b);
        }
    }
    printf("},\r\n");
    
    rd[xptN].inited=1;
}

#endif

#endif
